/*
 * @Author: xiaosihan
 * @Date: 2025-08-24 10:00:00
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2025-09-26 23:56:45
 */
import express from "express";
import ServiceBase from "./ServiceBase";
import database from "../database";
import { DataTypes, Op, QueryTypes, Sequelize } from 'sequelize';
import sequelize from "sequelize/types/sequelize";

// 数据服务类，用于处理设计数据和OSS文件数据的获取
export default class DataService extends ServiceBase {

    constructor(req: express.Request = {} as express.Request, res: express.Response = {} as express.Response) {
        super(req, res);
    }

    // 获取Design表数据
    get_design_data = async (params: Record<string, any>) => {
        // 参数验证
        this.verifyParams(['page', 'pageSize']);
        const page = parseInt(params.page as string) || 1;
        const pageSize = parseInt(params.pageSize as string) || 10;
        const onlyDuplicateData = params.onlyDuplicateData === 'true';
        const requireNonEmptyData = params.requireNonEmptyData === 'true' || params.requireNonEmptyData === true;
        const offset = (page - 1) * pageSize;

        // 构建基础查询条件
        const whereCondition: any = {};
        if (requireNonEmptyData) {
            whereCondition.data = {
                [Op.ne]: ''
            };
        }

        if (onlyDuplicateData) {
            // 查询非唯一的data值
            const duplicateData = await database.design.findAll({
                attributes: ['data', [Sequelize.fn('COUNT', 'id'), 'count']],
                group: ['data'],
                having: Sequelize.where(Sequelize.fn('COUNT', 'id'), '>', 1),
                raw: true,
                ...(requireNonEmptyData ? { where: { data: { [Op.ne]: '' } } } : {})
            });

            // 获取所有重复的data值
            const duplicateDataValues = duplicateData.map(item => item.data);

            // 查询数据并计算总数
            const [data, total] = await Promise.all([
                database.design.findAll({
                    where: {
                        ...whereCondition,
                        data: {
                            [Op.in]: duplicateDataValues
                        }
                    },
                    offset,
                    limit: pageSize,
                    order: [
                        ['order', 'ASC'], // 首先按order字段升序排序
                        ['id', 'DESC']    // 如果order相同，则按id降序排序
                    ]
                }),
                database.design.count({
                    where: {
                        ...whereCondition,
                        data: {
                            [Op.in]: duplicateDataValues
                        }
                    }
                })
            ]);

            return {
                data: data.map(item => {
                    const result = { ...item.dataValues };
                    // 将order字段只显示整数部分
                    if (result.order !== undefined) {
                        result.order = Math.floor(result.order);
                    }
                    return result;
                }),
                total
            };
        } else {
            // 原始查询逻辑，添加data非空条件
            const [data, total] = await Promise.all([
                database.design.findAll({
                    where: whereCondition,
                    offset,
                    limit: pageSize,
                    order: [
                        ['order', 'ASC'], // 首先按order字段升序排序
                        ['id', 'DESC']    // 如果order相同，则按id降序排序
                    ]
                }),
                database.design.count({ where: whereCondition })
            ]);

            return {
                data: data.map(item => {
                    const result = { ...item.dataValues };
                    // 将order字段只显示整数部分
                    if (result.order !== undefined) {
                        result.order = Math.floor(result.order);
                    }
                    return result;
                }),
                total
            };
        }
    };

    // 获取OSS文件表数据
    get_oss_file_data = async (params: Record<string, any>) => {
        // 参数验证
        this.verifyParams(['page', 'pageSize']);
        const page = parseInt(params.page as string) || 1;
        const pageSize = parseInt(params.pageSize as string) || 10;
        const used = params.used as string;
        const onlyDuplicateUrl = params.onlyDuplicateUrl === 'true';
        const offset = (page - 1) * pageSize;

        // 构建查询条件
        const whereCondition: any = {};
        if (used && ['unknown', 'nouse', 'used'].includes(used)) {
            whereCondition.used = used;
        }

        if (onlyDuplicateUrl) {
            // 查询非唯一的url值
            const duplicateUrls = await database.oss_file.findAll({
                attributes: ['url', [Sequelize.fn('COUNT', 'file_id'), 'count']],
                group: ['url'],
                having: Sequelize.where(Sequelize.fn('COUNT', 'file_id'), '>', 1),
                raw: true
            });

            // 获取所有重复的url值
            const duplicateUrlValues = duplicateUrls.map(item => item.url);

            // 添加到查询条件中
            whereCondition.url = {
                [Op.in]: duplicateUrlValues
            };
        }

        // 查询数据并计算总数
        const [data, total] = await Promise.all([
            database.oss_file.findAll({
                where: whereCondition,
                offset,
                limit: pageSize,
                order: [['file_id', 'DESC']]
            }),
            database.oss_file.count({ where: whereCondition })
        ]);

        return {
            data: data.map(item => item.dataValues),
            total
        };
    };

    // 重置OSS文件使用状态
    write_reset_oss_file_status = async (params: Record<string, any>) => {
        console.log('开始重置OSS文件使用状态...');

        // 更新oss_file表中所有记录的used字段为'unknown'
        const result = await database.oss_file.update(
            { used: 'unknown' },
            { where: {} } // 空条件表示更新所有记录
        );

        console.log(`成功重置了 ${result[0]} 条OSS文件的使用状态`);

        return {
            message: `成功重置了 ${result[0]} 条OSS文件的使用状态为未知`,
            resetCount: result[0]
        };
    };

    // 向Design表添加10条数据
    write_design_add = async (params: Record<string, any>) => {
        // 生成随机字符串的函数
        const generateRandomString = (length: number): string => {
            const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
            let result = '';
            for (let i = 0; i < length; i++) {
                result += chars.charAt(Math.floor(Math.random() * chars.length));
            }
            return result;
        };

        const totalRecords = 10;
        const allData: { data: string }[] = [];

        console.log(`开始生成 ${totalRecords} 条随机数据...`);

        // 先生成所有数据
        for (let i = 0; i < totalRecords; i++) {
            allData.push({ data: generateRandomString(200) });
        }

        console.log(`开始向 design 表插入 ${totalRecords} 条记录...`);

        // 直接插入10条数据
        await database.design.bulkCreate(allData, {
            ignoreDuplicates: true // 忽略重复记录
        });

        console.log(`已插入 ${totalRecords} 条记录`);

        // 重新计数
        const finalCount = await database.design.count();

        return {
            message: `成功向 design 表添加了 ${totalRecords} 条数据`,
            totalRecords,
            currentTableCount: finalCount
        };
    };


    // 重新排序Design数据
    write_design_reorder = async (params: Record<string, any>) => {
        // 参数验证
        this.verifyParams(['sourceId', 'targetOrder']);
        const sourceId = parseInt(params.sourceId as string);
        const targetOrder = parseInt(params.targetOrder as string);

        // 检查参数有效性
        if (isNaN(sourceId) || isNaN(targetOrder) || sourceId <= 0 || targetOrder < 0) {
            throw new Error('参数无效，请提供有效的sourceId和targetOrder');
        }

        // 查找要移动的数据
        const sourceData = await database.design.findByPk(sourceId);
        if (!sourceData) {
            throw new Error('未找到指定的数据源');
        }

        // 获取当前的排序值
        const currentOrder = sourceData.order || 0;

        // 如果目标位置与当前位置相同，直接返回成功
        if (currentOrder === targetOrder) {
            return {
                message: '数据已在指定位置，无需移动'
            };
        }

        // 事务处理，确保数据一致性
        await database.sequelize.transaction(async (transaction) => {
            // 根据移动方向调整其他记录的排序值
            if (targetOrder < currentOrder) {
                // 向上移动，目标位置及以上的记录order+1
                await database.design.update(
                    { order: database.sequelize.literal('`order` + 1') },
                    {
                        where: {
                            order: {
                                [Op.between]: [targetOrder, currentOrder - 1]
                            },
                            id: {
                                [Op.ne]: sourceId
                            }
                        },
                        transaction
                    }
                );
            } else {
                // 向下移动，目标位置及以下的记录order-1
                await database.design.update(
                    { order: database.sequelize.literal('`order` - 1') },
                    {
                        where: {
                            order: {
                                [Op.between]: [currentOrder + 1, targetOrder]
                            },
                            id: {
                                [Op.ne]: sourceId
                            }
                        },
                        transaction
                    }
                );
            }

            // 更新目标数据的排序值
            await sourceData.update({ order: targetOrder }, { transaction });
        });

        return {
            message: `成功将ID为${sourceId}的数据移动到位置${targetOrder}`
        };
    }


    // 随机设置Design表数据
    write_design_random_set = async (params: Record<string, any>) => {
        // 注意：当oss_file表和design表各有10万条数据时，需要注意内存和性能问题
        // 本实现采用分页查询Design数据，并为每条数据独立随机查询URL的方式

        // 获取OSS文件表的总数
        const totalOssFileCount = await database.oss_file.count({
            where: {
                url: {
                    [Op.not]: null
                }
            }
        });

        if (totalOssFileCount === 0) {
            throw new Error('oss_file表中没有可用的URL数据');
        }

        const totalDesignCount = await database.design.count();
        const batchSize = 1000; // 每批处理1000条记录
        let updatedCount = 0;

        // 分页查询并更新Design表数据
        for (let offset = 0; offset < totalDesignCount; offset += batchSize) {
            // 分批获取Design数据
            const batchDesignData = await database.design.findAll({
                offset,
                limit: batchSize
            });

            if (batchDesignData.length === 0) break;

            // 为当前批次数据生成要更新的值
            const updatePromises = batchDesignData.map(async (designData) => {
                try {
                    // 每条数据只随机查询1个URL
                    const randomOffset = Math.floor(Math.random() * totalOssFileCount);

                    // 查询单个随机URL
                    const randomUrlResult = await database.oss_file.findOne({
                        attributes: ['url'],
                        where: {
                            url: {
                                [Op.not]: null
                            }
                        },
                        offset: randomOffset,
                        limit: 1
                    });

                    // 如果查询到URL，就使用该URL，否则使用空字符串
                    const newData = randomUrlResult && randomUrlResult.url ? randomUrlResult.url : '';

                    // 更新数据
                    return database.design.update(
                        { data: newData },
                        { where: { id: designData.id } }
                    );
                } catch (error) {
                    console.error(`更新Design数据(ID: ${designData.id})失败:`, error);
                    // 出错时跳过该条记录，继续处理其他记录
                    return Promise.resolve();
                }
            });

            // 并行处理当前批次的更新
            await Promise.all(updatePromises);

            updatedCount += batchDesignData.length;
            console.log(`已更新 ${updatedCount}/${totalDesignCount} 条Design数据`);
        }

        return {
            message: `成功更新了${updatedCount}条Design数据`,
            updatedCount
        };
    };

    // 检查OSS文件URL使用状态
    get_oss_file_usage_status = async (params: Record<string, any>) => {
        console.log('开始检查OSS文件URL使用状态...');

        // 优化：增加批次大小以减少数据库交互次数
        const batchSize = 2000;
        let totalProcessed = 0;
        let totalUsed = 0;
        let offset = 0;

        // 循环处理所有OSS文件
        while (true) {
            // 获取当前批次的OSS文件
            const ossFiles = await database.oss_file.findAll({
                attributes: ['file_id', 'url'],
                offset,
                limit: batchSize,
                where: {
                    url: { [Op.not]: null }
                }
            });

            if (ossFiles.length === 0) break;

            // 优化1: 批量获取所有URL
            const urls = ossFiles.map(file => file.url);

            // 优化2: 使用INNER JOIN一次性查询所有存在的URL，避免循环中多次查询
            const usedUrls = await database.sequelize.query<{ data: string }>(
                `SELECT DISTINCT d.data FROM design AS d INNER JOIN oss_file AS o ON d.data = o.url WHERE o.url IN (:urls)`,
                {
                    replacements: { urls },
                    type: QueryTypes.SELECT
                }
            );

            // 构建已使用URL的集合，用于快速查找
            const usedUrlsSet = new Set(usedUrls.map(item => item.data));

            // 优化3: 批量准备需要更新的数据
            const updatePromises = [];

            // 处理当前批次的OSS文件
            for (const ossFile of ossFiles) {
                const url = ossFile.url;
                const usedStatus = usedUrlsSet.has(url) ? 'used' : 'nouse';

                // 添加到批量更新队列
                updatePromises.push(
                    database.oss_file.update(
                        { used: usedStatus },
                        { where: { file_id: ossFile.file_id } }
                    )
                );

                if (usedStatus === 'used') {
                    totalUsed++;
                }
            }

            // 优化4: 并行执行批量更新操作
            await Promise.all(updatePromises);

            totalProcessed += ossFiles.length;

            // 仅在批次数量是batchSize的5倍时输出进度日志，减少日志输出
            if (totalProcessed % (batchSize * 5) === 0) {
                console.log(`已处理 ${totalProcessed} 个OSS文件，其中 ${totalUsed} 个文件被使用`);
            }

            offset += batchSize;
        }

        // 仅保留最终完成的简要日志
        return {
            message: `OSS文件URL使用状态检查完成，共处理 ${totalProcessed} 个文件，其中 ${totalUsed} 个文件被使用`,
            totalProcessed,
            totalUsed
        };
    };

    // 查找匹配数据并更新（每次处理一对数据）
    match_and_update_data = async (params: Record<string, any>) => {
        const requireNonEmptyData = params.requireNonEmptyData === 'true' || params.requireNonEmptyData === true;

        // 构建SQL查询条件
        let whereCondition = 'o.used <> "nouse"';
        if (requireNonEmptyData) {
            whereCondition += ' AND d.data <> ""';
        }

        // 查找 design.data === oss_file.url 相等的数据
        // 使用原始SQL查询，因为两个模型之间没有定义关联关系
        const matchedRecords: any[] = await database.sequelize.query(`
            SELECT d.id AS designId, o.file_id AS ossFileId, d.data, o.url 
            FROM design AS d 
            INNER JOIN oss_file AS o ON d.data = o.url
            WHERE ${whereCondition}
            ORDER BY d.id ASC
            LIMIT 1
        `, {
            type: QueryTypes.SELECT
        });

        if (!matchedRecords || matchedRecords.length === 0) {
            return {
                message: '未找到匹配的数据',
                matched: false
            };
        }

        const { designId, ossFileId } = matchedRecords[0];

        if (!designId || !ossFileId) {
            return {
                message: '未找到匹配的OSS文件',
                matched: false
            };
        }

        // 开始事务
        const transaction = await database.sequelize.transaction();

        // 更新design表的data字段为空
        await database.design.update(
            { data: '' },
            {
                where: { id: designId },
                transaction
            }
        );

        // 更新oss_file表的used字段为nouse
        await database.oss_file.update(
            { used: 'nouse' },
            {
                where: { file_id: ossFileId },
                transaction
            }
        );

        // 提交事务
        await transaction.commit();

        return {
            message: '成功找到并更新了1条匹配的数据',
            matched: true,
            designId,
            ossFileId
        };
    };

    // 清空Design表data字段
    write_design_clear_data = async (params: Record<string, any>) => {
        // 更新design表中所有记录的data字段为空字符串
        const result = await database.design.update(
            { data: '' },
            { where: {} } // 空条件表示更新所有记录
        );

        return {
            message: `成功清空了 ${result[0]} 条Design数据的data字段`,
            clearCount: result[0]
        };
    };

    // 删除Design表全部数据
    del_design_all = async (params: Record<string, any>) => {
        // 删除design表中所有记录
        const result = await database.design.destroy({
            where: {} // 空条件表示删除所有记录
        });

        return {
            message: `成功删除了 ${result} 条Design数据`,
            deleteCount: result
        };
    };

    // 更新Design数据
    update_design_data = async (params: Record<string, any>) => {
        // 参数验证
        this.verifyParams(['id']);
        const { id, data = '', order: orderParam } = params;
        const designId = parseInt(id as string);
        let order = orderParam !== undefined ? parseFloat(orderParam as string) : null;

        // 验证ID的有效性
        if (isNaN(designId) || designId <= 0) {
            throw new Error('无效的设计ID');
        }

        // 开始事务
        const transaction = await database.sequelize.transaction();

        // 查询原始order值
        const originalDesign = await database.design.findByPk(designId, {
            attributes: ['order'],
            transaction
        });

        if (!originalDesign) {
            await transaction.rollback();
            throw new Error('未找到指定的设计记录');
        }

        // 根据用户要求，如果order值比原来的小就减小0.5，如果比原来的大就增加0.5
        if (order !== null) {
            const originalOrder = originalDesign.order || 0;
            if (order < originalOrder) {
                order -= 0.5;
            } else if (order > originalOrder) {
                order += 0.5;
            }
            // 如果order值与原值相同，则不做调整
        }

        // 更新数据
        await database.design.update(
            {
                data: data || '',
                order: order !== null ? order : 0
            },
            {
                where: { id: designId },
                transaction
            }
        );

        // 在更新完成后重新排序所有记录的order字段
        await this.resetDesignOrderInternal(transaction);

        // 提交事务
        await transaction.commit();

        // 无论是否有数据被修改（包括数据没有变化的情况），都返回成功
        // 注意：即使数据没有变化，我们也认为操作是成功的
        return {
            message: '数据更新成功！'
        };
    };

    // 内部方法：重新排序Design数据的order字段（支持事务）
    resetDesignOrderInternal = async (transaction: any) => {
        // 优化版：使用原生SQL语句，通过变量和ORDER BY子句一次完成排序和更新
        // 这种方式比原来的"先查询后批量更新"效率高得多，特别是对于大数据量

        // 初始化排序变量
        await database.sequelize.query(
            'SET @new_order = 0;',
            { transaction }
        );

        // 使用一条SQL语句完成所有记录的order字段重排
        const [result] = await database.sequelize.query(
            'UPDATE design ' +
            'SET `order` = (@new_order := @new_order + 1) ' +
            'ORDER BY `order` ASC',
            {
                type: QueryTypes.UPDATE,
                transaction
            }
        );

        // 获取总记录数用于日志输出
        const totalRecords = await database.design.count({
            transaction
        });

        console.log(`成功重新设置了 ${totalRecords} 条Design数据的order字段值`);

        return true;
    };

    // 重置Design表order字段值
    reset_design_order = async (params: Record<string, any>) => {
        console.log('开始重新设置Design表order字段值...');

        // 开始事务
        const transaction = await database.sequelize.transaction();

        await this.resetDesignOrderInternal(transaction);

        // 提交事务
        await transaction.commit();

        // 获取总记录数
        const totalRecords = await database.design.count();

        return {
            message: `成功重新设置了 ${totalRecords} 条Design数据的order字段值`,
            resetCount: totalRecords
        };
    };
    // 性能优化分析：
    // 当oss_file表和design表各有10万条数据时的内存和性能问题与优化策略：

    // 优化实现要点：
    // 1. **内存优化**：不再一次性加载大量数据到内存，而是采用分页处理策略
    // 2. **全表随机**：每条Design数据都从完整的OSS文件表中独立随机选择URL
    // 3. **分页处理**：Design数据分批处理，每批1000条，减少单次内存占用
    // 4. **错误处理**：每条数据的处理独立进行错误捕获，避免一条数据错误影响整体处理
    // 5. **进度监控**：添加处理进度日志，方便跟踪更新状态

    // 性能考量：
    // 1. 对10万条Design数据，每条都需要查询2-3次OSS文件表，总共会产生20-30万次查询
    // 2. 虽然查询次数增加，但每次查询只返回单条数据，数据库压力分散
    // 3. 实际生产环境中，可以根据服务器性能调整batchSize参数

    // 进一步优化建议：
    // 1. 添加数据库索引提升查询性能
    // 2. 考虑使用连接池管理数据库连接
    // 3. 对于超大数据量，可考虑使用消息队列实现异步处理
    // 4. 在业务允许的情况下，可以适当增加缓存机制减少数据库压力
}

// 导出服务类
// 类已在定义时导出